﻿using Autofac;
using Cyss.Core;
using Cyss.Core.Api.JWT;
using Cyss.Core.Cache;
using FluentValidation.AspNetCore;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Text.Encodings.Web;
using System.Text.Unicode;

namespace Cyss.Core.Api
{
    public static class ServiceCollectionExtensions
    {

        /// <summary>
        /// 注册核心服务
        /// </summary>
        /// <param name="services"></param>
        public static void RegisterCoreSerivce(this IServiceCollection services)
        {
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.AddSingleton<IIOCCore, ApiIOCCore>();
            services.AddScoped<IWorkContext, WebApiWorkContext>();
            services.AddScoped<IMessageContext, MessageContext>();
            services.AddSingleton<ITokenHelper, TokenHelper>();
            services.AddScoped<ApiKeyFiter>();
            services.AddScoped<IdempotenceAttribute>();
        }


        /// <summary>
        /// 注册Jwt Token 相关功能
        /// </summary>
        /// <param name="services"></param>
        /// <param name="Configuration"></param>
        public static void RegisterJwt(this IServiceCollection services, IConfiguration Configuration)
        {
            //读取配置文件配置的jwt相关配置
            services.Configure<JWTConfig>(Configuration.GetSection("JWTConfig"));
            //启用JWT
            services.AddAuthentication(Options =>
            {
                Options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                Options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).
            AddJwtBearer();
        }

        /// <summary>
        /// 启动Json
        /// </summary>
        /// <param name="services"></param>
        public static void AddJsonOptions(this IServiceCollection services)
        {

            services.AddControllersWithViews().AddJsonOptions(options =>
            {
                options.JsonSerializerOptions.PropertyNamingPolicy = null;
                options.JsonSerializerOptions.IgnoreNullValues = true;
                options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
                // options.JsonSerializerOptions.Converters.Add(new EncryptStringJsonConverter());
                //options.JsonSerializerOptions.Converters.Add(new OperateResultJsonConverterFactory());

            });
        }



        /// <summary>
        /// 加载所有继承自BaseConfig的配置
        /// </summary>
        /// <param name="services"></param>
        /// <param name="Configuration"></param>
        public static void RegisterAllConfig(this IServiceCollection services, IConfiguration Configuration)
        {
            var CustomAppsettingsPath = Configuration.GetValue<string>("CustomAppsettingsPath");
            if (string.IsNullOrWhiteSpace(CustomAppsettingsPath))
            {
                throw new Exception("请配置 CustomAppsettingsPath 路径信息！");
            }
            CustomAppsettingsPath = Path.GetFullPath(CustomAppsettingsPath);
            if (!System.IO.File.Exists(CustomAppsettingsPath))
            {
                throw new Exception($"配置文件不存在!{CustomAppsettingsPath}");
            }
            var builder = new ConfigurationBuilder().AddJsonFile(CustomAppsettingsPath, false, true);
            var _configuration = builder.Build();

            var types = AssembliesExtensions.UserAssemblies
                .SelectMany(a => a.GetTypes().Where(t => t.IsInterface == false && t.GetInterfaces().Contains(typeof(BaseConfig))))
                .ToArray();
            foreach (var type in types)
            {
                var configuration = _configuration.GetSection(type.Name);
                var config = Activator.CreateInstance(type) as BaseConfig;
                configuration.Bind(config);
                ConfigCore.AddConfig(config);
                services.AddSingleton(type, config);
            }
        }

        /// <summary>
        /// 注册所有实现了IBaseSerive接口 的服务
        /// </summary>
        /// <param name="services"></param>
        /// <param name="Configuration"></param>
        public static void RegisterAllService(this ContainerBuilder services)
        {
            var types = AssembliesExtensions.UserAssemblies.SelectMany(a => a.GetTypes().Where(t => t.BaseType != null && t.IsGenericType == false && t.BaseType.IsGenericType && t.BaseType.HasImplementedRawGeneric(typeof(IBaseService<>)))).ToArray();
            foreach (var type in types)
            {
                services.RegisterType(type).InstancePerLifetimeScope();
            }
        }
        private static IEnumerable<string> GetAssemblyNames()
        {
            return new string[] { "Account.Api.Client", "Account.Api.Dtos", "Common.Api.Client", "Common.Api.Dtos" ,
            "Cyss.Api.Client.Core","Cyss.Core.Api","Cyss.Core","Order.Api.Client","Order.Api.Dtos",
            "Outside.Api.Client","Outside.Api.Dtos","Product.Api.Client","Product.Api.Dtos","Report.Api.Client","Report.Api.Dtos" };
        }

        public static void AddFluentValidation(this IServiceCollection services)
        {
            services.AddMvc().AddFluentValidation(
               configuration =>
               {
                   //register all available validators from Nop assemblies
                   var assemblies = AssembliesExtensions.UserAssemblies.Where(x => x.FullName.Contains(".Dtos"));
                   configuration.RegisterValidatorsFromAssemblies(assemblies);
                   configuration.DisableDataAnnotationsValidation = true;
                   //implicit/automatic validation of child properties
                   configuration.ImplicitlyValidateChildProperties = true;
               }
               );


            services.Configure<ApiBehaviorOptions>(options =>
           {
               options.InvalidModelStateResponseFactory = (context) =>
               {
                   var errors = context.ModelState
                       .Values
                       .SelectMany(x => x.Errors
                                   .Select(p => p.ErrorMessage))
                       .ToList();

                   OperateResult OperateResult = new OperateResult();

                   OperateResult.IsSuccess = false;
                   OperateResult.Message = string.Join(Environment.NewLine, errors);
                   return new JsonResult(OperateResult);
               };
           });


        }

        public static void AddSwagger(this IServiceCollection services)
        {
            //添加Swagger
            services.AddSwaggerGen(c =>
            {
                var objectName = AppDomain.CurrentDomain.FriendlyName;
                var basePath = AppDomain.CurrentDomain.BaseDirectory;
                var xmlPath = Path.Combine(basePath, $"{objectName}.xml");
                if (System.IO.File.Exists(xmlPath))
                {
                    c.IncludeXmlComments(xmlPath);
                }
                var xmlModelPath = Path.Combine(basePath, $"{objectName}.Dtos.xml");
                if (System.IO.File.Exists(xmlModelPath))
                {
                    c.IncludeXmlComments(xmlModelPath);
                }
                c.SwaggerDoc("V1", new OpenApiInfo
                {
                    // {ApiName} 定义成全局变量，方便修改
                    Version = "V1",
                    Title = $"{objectName}接口文档",
                    Description = $"HTTP API V1"
                });
                c.OrderActionsBy(o => o.RelativePath);
            });
        }

        /// <summary>
        /// 开启记录api请求日志的中间件
        /// </summary>
        /// <param name="app"></param>
        /// <returns></returns>
        public static void UseSwaggerDocument(this IApplicationBuilder app)
        {
            //启用Swagger
            app.UseSwagger();
            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint($"/swagger/V1/swagger.json", $"V1");
                c.RoutePrefix = "";
            });
        }

        /// <summary>
        /// 注册数据库连接
        /// </summary>
        /// <param name="services"></param>
        public static void RegisterConnectionString<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TConnectionString>(this IServiceCollection services) where TConnectionString : class, IConnectionString
        {
            services.AddSingleton<IConnectionString, TConnectionString>();
        }

        /// <summary>
        /// 注册用户权限验证服务
        /// </summary>
        /// <param name="services"></param>
        public static void RegisterPermissionService<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TPermissionVerification>(this IServiceCollection services) where TPermissionVerification : class, IPermissionVerification
        {
            services.AddScoped<PermissionAttribute>();
            services.AddSingleton<IPermissionVerification, TPermissionVerification>();
        }

        /// <summary>
        /// 注册redis 缓存服务
        /// </summary>
        /// <param name="services"></param>
        public static void RegisterRedisCacheService(this IServiceCollection services)
        {

            services.AddSingleton<IRedisConnectionWrapper, RedisConnectionWrapper>();
            services.AddSingleton<IStaticCacheManager, RedisCacheManager>();
        }

        ///// <summary>
        ///// 注册RabbitMQ消息队列服务
        ///// </summary>
        //public static void RegisterRabbitMQService(this IServiceCollection services)
        //{
        //    services.AddSingleton<IRabbitMQPersistentConnection, DefaultRabbitMQPersistentConnection>();
        //    services.AddSingleton<RabbitMQService>();
        //}

        /// <summary>
        /// 注册api自动缓存服务
        /// </summary>
        /// <param name="services"></param>
        public static void RegisterCacheAttributeService(this IServiceCollection services)
        {
            services.AddScoped<CacheAttribute>();
        }



    }
}
